package sdu.icat.pj.shiro;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.session.data.redis.RedisOperationsSessionRepository;
import org.springframework.stereotype.Repository;

import sdu.icat.pj.service.SysSessionService;
import sdu.icat.pj.service.SysUserService;
import sdu.icat.pj.util.WebUtil;
import sdu.icat.sys.smodel.SysSession;
import sdu.icat.sys.smodel.SysUser;

/**
 * 
 * 权限检查类
 * @author ljh_2015
 *
 */
public class Realm extends AuthorizingRealm {

    private Logger logger = LogManager.getLogger();

    @Autowired SysUserService sysUserService;

    @Autowired SysSessionService sysSessionService;

    @Autowired RedisOperationsSessionRepository sessionRepository;
    
    
    @Override
    //权限
    protected AuthorizationInfo doGetAuthorizationInfo(
	    PrincipalCollection principals) {
	SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
	Long userId = (Long) WebUtil.getCurrentUser();
	List<String> list = sysUserService.queryPermissionByUserId(userId);
	for(String permission:list) {
	    if(StringUtils.isNoneBlank(permission)) {
		info.addStringPermission(permission);
	    }
	}
	//添加用户权限
	info.addStringPermission("user");
	return info;
    }

    @Override
    //登录验证
    protected AuthenticationInfo doGetAuthenticationInfo(
	    AuthenticationToken authctoken) throws AuthenticationException {
	UsernamePasswordToken token = (UsernamePasswordToken) authctoken;
	Map<String,Object> params = new HashMap<>();
	params.put("enable", 1);
	params.put("account", token.getUsername());
	String username = token.getUsername();
	char[] password = token.getPassword();
	SysUser user = sysUserService.queryOne(username);
	if(user!=null) {
	    StringBuilder sb = new StringBuilder(100);
	    for(int i=0;i<password.length;i++) {
		sb.append(password[i]);
	    }

	    if(user.getPassword().equals(sb.toString())) {
		//session操作,保存会话
		WebUtil.saveCurrentUser(user);
		saveSession(user.getAccount(), token.getHost());
		AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(user.getAccount(),
			user.getPassword(),user.getUserName());
		return authcInfo;
	    }
	    logger.warn("USER [{}] PASSWORD IS WRONG: {}",token.getUsername(),sb.toString());
	    return null;
	} else {
	    logger.warn("No user:{}",username);
	    return null;
	}
    }

    private void saveSession(String account,String host) {
	SysSession record = new SysSession();
	record.setAccount(account);
	List<SysSession> sessionIds = sysSessionService.querySessionIdByAccount(account);
	Subject currentUser = SecurityUtils.getSubject();
	Session session = currentUser.getSession();
	String currentSessionId = session.getId().toString();
	if(sessionIds != null) {
	    for(SysSession sessionId:sessionIds) {
		record.setSessionId(sessionId.getSessionId());
		sysSessionService.deleteBySessionId(sessionId);
		if(!currentSessionId.equals(sessionId.getSessionId())) {
		    sessionRepository.delete(sessionId.getSessionId());
		    sessionRepository.cleanupExpiredSessions();
		}
	    }
	}

	record.setSessionId(currentSessionId);
	record.setIp(StringUtils.isBlank(host) ? session.getHost():host);
	record.setStartTime(session.getStartTimestamp());
	sysSessionService.update(record);
    }

}
